import {
    db, UserModel, SettingModel, DomainModel, Handler, UserNotFoundError, UserAlreadyExistError, ValidationError, MessageNotFoundError, PrivilegeError, param, PERM, PRIV, Types, query, MessageModel, requireSudo
} from 'hydrooj';

const coll = db.collection('message');

//展示所有用户
class ManageUsersHandler extends Handler {
    @query('page', Types.PositiveInt, true)
    @query('groupName', Types.string, true)
    @query('banStatus', Types.string, true)
    async get(domainId: string, page = 1, groupName: string, banStatus: string) {

        let filter = { _id: { $gte: 2 } };

        const groups = await UserModel.listGroup(domainId);
        if (groupName) {
            const groupInfo = groups.find(g => g.name === groupName);
            if (groupInfo) {
                filter._id = { $in: groupInfo.uids };
            }
        }

        // 添加封禁状态筛选逻辑
        if (banStatus === 'banned') {
            filter.priv = PRIV.PRIV_NONE;  // 封禁用户权限为0
        } else if (banStatus === 'active') {
            filter.priv = { $ne: PRIV.PRIV_NONE };  // 未封禁用户权限不为0
        }

        const [dudocs, upcount] = await this.paginate(
            UserModel.getMulti(filter).sort({ _id: -1 }),
            page,
            'ranking'
        );
        const udict = await UserModel.getList(domainId, dudocs.map((x) => x._id));
        const udocs = dudocs.map((x) => udict[x._id]);
        this.response.template = 'manage_users.html'; // 返回此页面
        this.response.body = { udocs, upcount, page, groupName, groups, banStatus };
    }

    @param('uid', Types.Int)
    async post(domainId: string, uid: number) {
        await UserModel.ban(uid);
        this.response.body = { success: true };
    }
}

//展示所有消息
class ManageMessageHandler extends Handler {
    @requireSudo
    @query('uid', Types.Int, true)
    @query('page', Types.PositiveInt, true)
    async get(domainId: string,uid = 0, page = 1) {
        const udoc = await UserModel.getById(domainId, uid);
        const filter = uid === 0 ? coll.find().sort({ _id: -1 }) : MessageModel.getMulti(uid).sort({ _id: -1 });
        const [mdocs, upcount] = await this.paginate(filter,page,10);

        // 获取所有相关的用户信息
        const uids = new Set<number>([
            ...mdocs.map((mdoc) => mdoc.from),
            ...mdocs.map((mdoc) => mdoc.to),
        ]);
        const udict = await UserModel.getList(domainId, Array.from(uids));

        this.response.template = 'manage_message.html'; // 返回此页面
        this.response.body = { uid, mdocs, upcount, page, udict };
    }

    //删除消息
    @param('id', Types.ObjectId)
    async postDelete(domainId: string, id: ObjectId) {
        const message = await MessageModel.get(id);
        if (!message) throw new MessageNotFoundError(id);
        await MessageModel.del(id);
        this.response.body = { success: true };
    }
}

//修改用户名
class ManageChangeUnameHandler extends Handler {
    @requireSudo
    @query('uidOrName', Types.UidOrName, true)
    async get(domainId: string, uidOrName: string) {
        this.response.template = 'manage_changeuname.html'; // 返回此页面
        this.response.body = { uidOrName };
    }
    @param('uidOrName', Types.UidOrName)
    @param('newUname', Types.Username)
    async post(domainId: string, uidOrName: string, newUname: string) {
        // 检查输入
        if (/^[+-]?\d+$/.test(newUname.trim()))
            throw new ValidationError(newUname,'',`用户名不能为纯数字`);
        const udoc = await UserModel.getById(domainId, +uidOrName)
            || await UserModel.getByUname(domainId, uidOrName)
            || await UserModel.getByEmail(domainId, uidOrName);
        if (!udoc)
            throw new UserNotFoundError(uidOrName);
        const udoc2 = await UserModel.getById(domainId, +newUname)
            || await UserModel.getByUname(domainId, newUname)
            || await UserModel.getByEmail(domainId, newUname);
        if (udoc2)
            throw new UserAlreadyExistError(newUname);

        if ((udoc.hasPriv(PRIV.PRIV_SET_PERM) || udoc.hasPriv(PRIV.PRIV_EDIT_SYSTEM)) && udoc._id !== this.user._id) {
            this.checkPriv(PRIV.PRIV_ALL);
        }

        // 修改用户名
        await UserModel.setUname(udoc._id, newUname);
        this.response.body = { success: true };
    }
}

//用户修改用户名
class UnameChangeHandler extends Handler {
    async get() {
        this.response.template = 'uname_change.html'; // 返回此页面
    }
    @param('password', Types.Password)
    @param('newUname', Types.Username)
    async post(domainId: string, password: string, newUname: string) {
        // 检查输入
        if (/^[+-]?\d+$/.test(newUname.trim()))
            throw new ValidationError(newUname,'',`用户名不能为纯数字`);
        if (this.user.olduname)
            throw new ValidationError('修改次数','',`修改次数已达上限`);
        const udoc = await UserModel.getById(domainId, +newUname)
            || await UserModel.getByUname(domainId, newUname)
            || await UserModel.getByEmail(domainId, newUname);
        if (udoc)
            throw new UserAlreadyExistError(newUname);
        await this.user.checkPassword(password);
        // 修改用户名
        await UserModel.setById(this.user._id, { olduname: this.user.uname });
        await UserModel.setUname(this.user._id, newUname);
        this.response.body = { success: true };
    }
}

class ManageFilesHandler extends Handler {
    @requireSudo
    @query('page', Types.PositiveInt, true)
    async get(domainId: string, page = 1) {

        const [dudocs, upcount] = await this.paginate(
            UserModel.getMulti({ '_files.0': { $exists: true } }),
            page,
            'ranking'
        );
        const udict = await UserModel.getList(domainId, dudocs.map((x) => x._id));
        const udocs = dudocs.map((x) => udict[x._id]);
        this.response.template = 'manage_files.html'; // 返回此页面
        this.response.body = { udocs, upcount, page };
    }
}

class DomainImportHandler extends Handler {
    async get() {
        this.response.body.users = [];
        this.response.template = 'domain_import.html';
    }

    @param('users', Types.Content)
    @param('draft', Types.Boolean)
    async post(domainId: string, _users: string, draft: boolean) {
        const users = _users.split('\n');
        const udocs: { username: string, role: string, group: string }[] = [];
        const messages = [];

        for (const i in users) {
            const u = users[i];
            if (!u.trim()) continue;
            let [username, role, group] = u.split('\t').map((t) => t.trim());
            if (username && !role && !group) {
                const data = u.split(',').map((t) => t.trim());
                [username, role, group] = data;
            }

            if (!username) continue;

            // 验证用户是否存在
            const user = await UserModel.getByUname(domainId, username);
            if (!user) {
                messages.push(`Line ${+i + 1}: User ${username} not found.`);
                continue;
            }

            // 获取域中所有可用角色
            const availableRoles = await DomainModel.getRoles(domainId);
            const roleNames = availableRoles.map(role => role._id);
            if (role && !roleNames.includes(role)) {
                messages.push(`Line ${+i + 1}: Role ${role} does not exist.`);
                continue;
            }

            udocs.push({
                username, role, group
            });
        }
        messages.push(`${udocs.length} verify records found.`);

        if (!draft) {
            const existing = await UserModel.listGroup(domainId);
            const groups: Record<string, number[]> = Object.create(null);

            for (const udoc of udocs) {
                try {
                    const user = await UserModel.getByUname(domainId, udoc.username);
                    if (!user) continue;
                    if (udoc.role)
                        await DomainModel.setUserRole(domainId, user._id, udoc.role, true);
                    if (udoc.group) {
                        groups[udoc.group] ||= [];
                        groups[udoc.group].push(user._id);
                    }
                } catch (e) {
                    messages.push(e.message);
                }
            }
            for (const name in groups) {
                const uids = groups[name];
                const current = existing.find((i) => i.name === name)?.uids || [];
                if (uids.length) await UserModel.updateGroup(domainId, name, Array.from(new Set([...current, ...uids])));
            }
        }
        this.response.body.users = udocs;
        this.response.body.messages = messages;
    }
}

// 配置项及路由
export async function apply(ctx: Context) {
    ctx.inject(['setting'], (c) => {
        c.setting.AccountSetting(
            SettingModel.Setting('setting_info', 'olduname', '', 'text', '姓名', null, 3)
        );
    });

    ctx.on('handler/before/DomainRank#get', async (h) => {
        const { domainId, groupName } = h.args;
        const page = parseInt(h.args.page) || 1;
        let filter = { uid: { $gt: 1 }, rp: { $gt: 0 } };
        const groups = await UserModel.listGroup(domainId);
        if (groupName) {
            const groupInfo = groups.find(g => g.name === groupName);
            if (groupInfo) {
                filter.uid = { $in: groupInfo.uids };
            }
        }
        const [dudocs, upcount] = await h.paginate(
            DomainModel.getMultiUserInDomain(domainId, filter).sort({ rp: -1 }),
            page,
            'ranking'
        );
        const udict = await UserModel.getList(domainId, dudocs.map((dudoc) => dudoc.uid));
        const udocs = dudocs.map((i) => udict[i.uid]);
        h.response.template = 'ranking.html';
        h.response.body = { udocs, upcount, page, groupName, groups };
        return 'after';
    });

    ctx.on('handler/before/SwitchAccount#get', async (h) => {
        const { uid, domainId } = h.args;
        const targetUser = await UserModel.getById(domainId, uid);

        // 检查权限限制：如果当前用户没有PRIV_ALL，不能切换到有PRIV_ALL的用户
        if (!h.user.hasPriv(PRIV.PRIV_ALL) && targetUser.hasPriv(PRIV.PRIV_ALL)) {
            throw new PrivilegeError(PRIV.PRIV_ALL);
        }
    });

    const systemHandlers = [ 'SystemScriptHandler', 'SystemUserPrivHandler', 'SystemSettingHandler', 'SystemConfigHandler' ];
    systemHandlers.forEach(handlerName => {
        ctx.server.applyMixin(handlerName, {
            async prepare() {
                this.checkPriv(PRIV.PRIV_ALL);
            }
        });
    });

    ctx.Route('用户管理', '/manage/users', ManageUsersHandler, PRIV.PRIV_EDIT_SYSTEM);
    ctx.Route('消息管理', '/manage/message', ManageMessageHandler, PRIV.PRIV_ALL);
    ctx.Route('文件管理', '/manage/files', ManageFilesHandler, PRIV.PRIV_ALL);
    ctx.Route('uname_change', '/uname/change', UnameChangeHandler, PRIV.PRIV_USER_PROFILE);
    ctx.Route('manage_changeuname', '/manage/changeuname', ManageChangeUnameHandler, PRIV.PRIV_EDIT_SYSTEM);
    ctx.Route('批量设置用户权限','/domain/import', DomainImportHandler,PERM.PERM_EDIT_DOMAIN);
    ctx.injectUI('DomainManage', '批量设置用户权限',{ family: 'Access Control', icon: 'user' });
    ctx.injectUI('ControlPanel', '用户管理');
    ctx.injectUI('ControlPanel', '消息管理');
    ctx.injectUI('ControlPanel', '文件管理');
}
